#include "RTC.h" 
uint8_t Year=0;
uint8_t Month=0;
uint8_t Day=0;

uint8_t Hour=0;
uint8_t Minute=0;
uint8_t Second=0;


_calendar_obj calendar;                                                       //时钟结构体 
/***************************************************************************/
//*******函数名: void RTC_IRQHandler()
//*******说  明：RTC时钟的中断服务函数
//*******参  数：无参数
//*******返回值：无返回
/***************************************************************************/
void RTC_IRQHandler()
{
    RTC_Get();         //获取时间
    RTC_ClearITPendingBit(RTC_IT_SEC);
}

void RtcNvicInit(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;                                      //定义中断初始化结构体
    NVIC_InitStructure.NVIC_IRQChannel=RTC_IRQn;                              //使能RTC中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;                      //先占优先级0级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;                          //从优先级0级
    NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;                              //使能外部中断通道
    NVIC_Init(&NVIC_InitStructure);                                           //参数初始化外设NVIC寄存器
}
/***************************************************************************/
//*******函数名：Rtc_Init()
//*******说  明：RTC时钟初始化
//*******参  数：无参数
//*******返回值：无返回
/***************************************************************************/
u8 Rtc_Init(void)
{
    u8 temp=0;
    RtcNvicInit();
    if(BKP_ReadBackupRegister(BKP_DR1) != 0XA0A0)                             //从后备寄存器读数据,判断是否需要更新RTC
    {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR|RCC_APB1Periph_BKP, ENABLE);//使能PWR和BKP外设时钟   
        PWR_BackupAccessCmd(ENABLE);                                          //使能后备寄存器访问 
        BKP_DeInit();                                                          //复位备份区域     
        RCC_LSEConfig(RCC_LSE_ON);                                              //设置外部低速晶振(LSE),使用外设低速晶振
        while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)                      //检查指定的RCC标志位设置与否,等待低速晶振就绪 
        {
            temp++;                                                              //等待
            delay_ms(10);
        }
        if(temp >= 250)
        return 1;                                              //时钟初始化失败
        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);                               //使能RTC时钟，低速的外部时钟
        RCC_RTCCLKCmd(ENABLE);                                                  //使能RTC时钟
        RTC_WaitForLastTask();                                                //等待最近一次对RTC操作完成
        RTC_WaitForSynchro();                                                 //等待RTC寄存器与APB时钟同步
        RTC_EnterConfigMode();                                                //进入RTC配置模式     
        RTC_WaitForLastTask();                                                //等待最近一次对RTC操作完成
        RTC_SetPrescaler(32767);                                              //RTC的预分频值
        RTC_WaitForLastTask();                                                //等待最近一次对RTC操作完成
        RTC_Set(2016,05,12,10,30,0);                                           //设置RTC寄存器值时间
        RTC_WaitForLastTask();                                                //等待最近一次对RTC操作完成
        RTC_ITConfig(RTC_IT_SEC,ENABLE);                                      //使能秒中断
        RTC_WaitForLastTask();                                                //等待最近一次对RTC操作完成
        RTC_ExitConfigMode();                                                 //退出配置模式
        BKP_WriteBackupRegister(BKP_DR1,0XA0A0);                              //向指定的后备寄存器中写入用户程序数据
    }
    else
    {
        RTC_WaitForLastTask();                                                //等待最近一次对RTC操作完成
        RTC_ITConfig(RTC_IT_SEC,ENABLE);                                      //使能秒中断
        RTC_WaitForLastTask();                                                //等待最近一次对RTC操作完成
    }
    return 0; 
}
//年份周期表
//月份   1  2  3  4  5  6  7  8  9  10 11 12
//闰年   31 29 31 30 31 30 31 31 30 31 30 31
//非闰年 31 28 31 30 31 30 31 31 30 31 30 31
/***************************************************************************/
//*******函数名：Is_LeapYear()
//*******说  明：判断是不是润年
//*******参  数：年份
//*******返回值：判断该年份是不是润年，是1，不是0；
/***************************************************************************/
u8 Is_LeapYear(u16 year)
{              
    if(year%4==0)                                                             //必须能被4整除
    { 
        if(year%100==0)                                              
        {                                                                       //对100取余
            if(year%400==0)
            {
                return 1;                                                     //如果以00结尾,还要能被400整除 
            }       
            else return 0;                                                    //闰年
        }
        else return 1;                                                           //平年
    }                                                                        
    else return 0;    
}                                                                              //平年                                                                     
const u8 mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};                 //平年的月份日期表
/***************************************************************************/
//*******函数名：RTC_Set()
//*******说  明：设置时间
//*******参  数：把输入的时钟转换为秒钟,以1970年1月1日为基准,1970~2099年为合法年份
//*******返回值：1:设置失败    0:设置成功
/***************************************************************************/
u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
{
    u16 t;
    u32 seccount=0;
    if(syear<1970||syear>2099)return 1;                                           //判断是不是合法年 
    if(smon > 12)return 1;                                                       //判断是不是合法月                    
    if(sday > 31)return 1;                                                       //判断是不是合法日
    if(hour > 24)return 1;                                                       //判断是不是合法时
    if(min > 60)return 1;                                                        //判断是不是合法分
    if(sec > 60)return 1;                                                        //判断是不是合法秒
    
    for(t=1970;t<syear;t++)                                                          //把所有年份的秒钟相加
    {
        if(Is_LeapYear(t))seccount+=31622400;                                   //闰年的秒钟数
        else seccount+=31536000;                                                 //平年的秒钟数
    }
    smon-=1;                                                                     //0是有效位
    for(t=0;t<smon;t++)                                                             //把前面月份的秒钟数相加
    {
        seccount+=(u32)mon_table[t]*86400;                                       //月份秒钟数相加
        if(Is_LeapYear(syear)&&t==1)seccount+=86400;                           //闰年2月份增加一天的秒钟数       
    }
    seccount+=(u32)(sday-1)*86400;                                             //把前面日期的秒钟数相加 
    seccount+=(u32)hour*3600;                                                  //小时秒钟数
    seccount+=(u32)min*60;                                                       //分钟秒钟数
    seccount+=sec;                                                             //最后的秒钟加上去

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);   //使能PWR和BKP外设时钟  
    PWR_BackupAccessCmd(ENABLE);                                               //使能RTC和后备寄存器访问                     
    RTC_SetCounter(seccount);                                                   //设置RTC计数器的值
    RTC_WaitForLastTask();                                                         //等待最近一次对RTC寄存器的写操作完成      
    return 0;                                                                   //设置成功
}
/***************************************************************************/
//*******函数名：RTC_Get()
//*******说  明：更新时间
//*******参  数：
//*******返回值：当前时间
/***************************************************************************/
u8 RTC_Get(void)
{
    static u16 daycnt=0;
    u32 timecount=0; 
    u32 temp=0;
    u16 temp1=0;      
     timecount=RTC->CNTH;                                                       //高位
    timecount<<=16;                                                               //低位
    timecount+=RTC->CNTL;                                                        //得到计数器中的值(秒钟数)
    
     temp=timecount/86400;                                                      //得到天数(秒钟数对应的)
    if(daycnt!=temp)                                                           //判断有没有超过一天
    {      
        daycnt=temp;                                                           //赋值
        temp1=1970;                                                               //从1970年开始
        while(temp>=365)
        {                 
            if(Is_LeapYear(temp1))                                               //是闰年
            {
                if(temp>=366)temp-=366;                                        //闰年的天数
                else {temp1++;break;}                                             //年份自增
            }
            else temp-=365;                                                       //平年 
            temp1++;                                                           //年份自增            
        }   
        calendar.w_year=temp1;                                                 //得到年份
        Year=(uint8_t)(calendar.w_year-2000);
        temp1=0;
        while(temp>=28)                                                        //超过了一个月
        {
            if(Is_LeapYear(calendar.w_year)&&temp1==1)                         //当年是不是闰年/2月份
            {
                if(temp>=29)temp-=29;                                          //闰年的秒钟数
                else break; 
            }
            else 
            {
                if(temp>=mon_table[temp1])temp-=mon_table[temp1];              //平年
                else break;
            }
            temp1++;  
        }
        calendar.w_month=temp1+1;                                               //得到月份
        Month=calendar.w_month;
        calendar.w_date=temp+1;                                                 //得到日期 
        Day=calendar.w_date;
    }
    temp=timecount%86400;                                                        //得到秒钟数          
    calendar.hour=temp/3600;                                                    //小时
    Hour=calendar.hour;
    calendar.min=(temp%3600)/60;                                                //分钟
    Minute=calendar.min;    
    calendar.sec=(temp%3600)%60;                                                //秒钟
    Second=calendar.sec;
    calendar.week=RTC_Get_Week(calendar.w_year,calendar.w_month,calendar.w_date);//获取星期   
    return 0;
}
/***************************************************************************/
//*******函数名：RTC_Get_Week()
//*******说  明：获得现在是星期几
//*******参  数：输入公历日期得到星期(只允许1901-2099年)
//*******返回值：星期号
/***************************************************************************/
u8 const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5};                            //月修正数据表                                                                                             
u8 RTC_Get_Week(u16 year,u8 month,u8 day)
{    
    u16 temp2;
    u8 yearH,yearL;
    
    yearH=year/100;    yearL=year%100;                                           //如果为21世纪,年份数加100  
    if (yearH>19)yearL+=100;                                                  //所过闰年数只算1900年之后的  
    temp2=yearL+yearL/4;
    temp2=temp2%7; 
    temp2=temp2+day+table_week[month-1];                                      //月修正数据表
    if (yearL%4==0&&month<3)temp2--;                                            //自减
    return(temp2%7);                                                                                     //返回星期
}

